package com.febs.security.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.febs.common.domain.FebsConstant;
import com.febs.common.domain.ResponseBo;
import com.febs.security.domain.FebsLoginUser;
import com.febs.security.domain.FebsSocialUserDetails;
import com.febs.security.domain.FebsUserDetails;
import com.febs.security.domain.LoginType;
import com.febs.security.helper.FebsJwtTokenHelper;
import com.febs.security.properties.FebsSecurityProperties;
import com.febs.system.domain.Role;
import com.febs.system.service.RoleService;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.bean.BeanUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 登录成功处理器
 */
@Slf4j
@Configuration
public class FebsAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private ObjectMapper mapper = new ObjectMapper();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Resource
    private SessionRegistry sessionRegistry;
    @Resource
    private FebsSecurityProperties febsSecurityProperties;
    @Resource
    private FebsJwtTokenHelper febsJwtTokenHelper;
    @Resource
    private RoleService roleService;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException {
        WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
        String remoteAddress = details.getRemoteAddress();

        String token;
        FebsLoginUser loginUser = new FebsLoginUser();
        LoginType loginType = LoginType.normal;
        Object principal = authentication.getPrincipal();
        if (principal instanceof FebsUserDetails) {
            FebsUserDetails userDetails = (FebsUserDetails) principal;
            userDetails.setRemoteAddress(remoteAddress);
            loginType = userDetails.getLoginType();
            loginUser = BeanUtil.copyProperties(userDetails, FebsLoginUser.class);
        }
        if (principal instanceof FebsSocialUserDetails) {
            FebsSocialUserDetails userDetails = (FebsSocialUserDetails) principal;
            userDetails.setRemoteAddress(remoteAddress);
            loginType = userDetails.getLoginType();
            loginUser = BeanUtil.copyProperties(userDetails, FebsLoginUser.class);
        }
        // 查询角色信息
        List<Role> roles = roleService.findUserRole(loginUser.getUsername());
        loginUser.setRoles(roles);
        // 权限信息
        List<String> authorities = loginUser.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        loginUser.setPermissions(authorities);
        // 缓存用户信息
        token = febsJwtTokenHelper.generateToken(loginUser);

        // 解决第三方登录在 session 并发控制设置不生效的问题
        if (!LoginType.normal.equals(loginType)) {
            String sessionId = details.getSessionId();
            sessionRegistry.removeSessionInformation(sessionId);
            sessionRegistry.registerNewSession(sessionId, authentication.getPrincipal());

            ConcurrentSessionControlAuthenticationStrategy authenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);

            // 手动设置最大并发登录数量，因为在 sessionManagement 中设置的 maximumSessions
            // 只对账号密码登录的方式生效 =。=
            authenticationStrategy.setMaximumSessions(febsSecurityProperties.getSession().getMaximumSessions());
            authenticationStrategy.onAuthentication(authentication, request, response);

            // 社交账户登录成功后直接 重定向到主页
            if (LoginType.social.equals(loginType)) {
                redirectStrategy.sendRedirect(request, response, febsSecurityProperties.getIndexUrl());
            }
        }
        response.setContentType(FebsConstant.JSON_UTF8);
//        response.setHeader(febsSecurityProperties.getToken().getHeader(), FebsConstant.TOKEN_PREFIX + token);
        ResponseBo bo = ResponseBo.ok();
        bo.put("token", token);
        bo.put("key", febsJwtTokenHelper.getUuidFromToken(token));
        bo.put("user", loginUser);
        bo.put("permissions", authorities);
        bo.put("roles", roles);
        response.getWriter().write(mapper.writeValueAsString(bo));
        log.info(FebsConstant.TOKEN_PREFIX + token);
//        redirectStrategy.sendRedirect(request, response, febsSecurityProperties.getIndexUrl());
    }
}
